package cmd

import (
	"fmt"
	"reflect"
	"strings"

	"gitee.com/night-tc/gobige/common"
	"gitee.com/night-tc/gobige/logger"
)

/*
命令管理器
*/
// CmdMgr 管理所有命令的注册与解析
type CmdMgr struct {
	CmdList map[CmdTypeEnum]*CmdInfo // 命令列表
}

// newCmdMgr 创建新的命令管理器
func newCmdMgr() *CmdMgr {
	mgr := new(CmdMgr)
	mgr.CmdList = make(map[CmdTypeEnum]*CmdInfo)
	return mgr
}

// RegisterCmd 注册一个普通命令
func (this *CmdMgr) RegisterCmd(cmdName CmdTypeEnum, note string, runf RunCmdF, param ...*ParamInfo) {
	cmd := new(CmdInfo)
	cmd.CmdName = cmdName
	cmd.CmdNote = note
	cmd.ParamList = make(map[string]*ParamInfo)
	cmd.Runf = runf
	for _, p := range param {
		cmd.ParamList[p.ParamName] = p
	}
	this.CmdList[cmd.CmdName] = cmd
}

// RegisterLogic 注册一个逻辑命令
func (this *CmdMgr) RegisterLogic(cmdName CmdTypeEnum, note string, lg ILogic) {
	cmd := new(CmdInfo)
	cmd.CmdName = cmdName
	cmd.CmdNote = note
	cmd.ParamList = make(map[string]*ParamInfo)
	cmd.Parsef = lg.ParseCmd
	cmd.LogicType = reflect.TypeOf(lg).Elem()
	lg.GenCmdParam(cmd)
	this.CmdList[cmd.CmdName] = cmd
}

// String 返回所有注册命令的字符串描述
func (this *CmdMgr) String() string {
	sb := common.NewStringBuilder()
	sb.Appendln("所有注册的指令：")
	for k, v := range this.CmdList {
		sb.Appendln(fmt.Sprintf("%s\t%s", k, v.CmdNote))
	}
	sb.Appendln("想查看具体指令使用：[cmd] -h cmd 为具体的指令")
	return sb.ToString()
}

// SendCmd 解析输入的命令字符串，返回命令对象
func (this *CmdMgr) SendCmd(cmdstr string) (result *InputCmd) {
	if cmdstr == "" {
		return
	}
	cmdli := strings.Split(cmdstr, " ")
	cmdkey := CmdTypeEnum(cmdli[0])
	if cmdkey == Cmd_Help {
		//显示帮助
		logger.Info(this)
		return
	}
	cmdinfo, ok := this.CmdList[cmdkey]
	if !ok {
		logger.Warnf("没有找到指定的命令：%s 可以使用help查看所有指令", cmdkey)
		return
	}
	result = new(InputCmd)
	result.Param = make(map[string]string)
	result.Cmd = cmdinfo
	i := 1
	var param *ParamInfo
	for len(cmdli) > i {
		curkey := cmdli[i]
		if curkey == "" {
			i++
			continue
		}
		if curkey[0] == '-' {
			s := curkey[1:]
			if s == "h" {
				//查看帮助
				logger.Warn(cmdinfo)
				return nil
			}
			param, ok = cmdinfo.ParamList[s]
			if !ok {
				logger.Warnf("不认识参数：%s", s)
				logger.Warn(cmdinfo)
				return nil
			}
			i++
		} else if param == nil {
			logger.Warnf("参数不匹配。")
			logger.Warn(cmdinfo)
			return nil
		} else {
			result.Param[param.ParamName] = curkey
			param = nil
			i++
		}
	}
	if param != nil {
		logger.Warnf("参数不匹配。")
		logger.Warn(cmdinfo)
		return nil
	}
	return
}

// CmdInfo 命令详细信息
type CmdInfo struct {
	// 命令本身
	CmdName CmdTypeEnum
	// 命令说明
	CmdNote string
	// 参数集合
	ParamList map[string]*ParamInfo
	// 生成参数后，需要运行的方法 如果是直接命令，走这个
	Runf RunCmdF
	// 解析命令
	Parsef ParseCmdF
	// 逻辑类型
	LogicType reflect.Type
}

// String 返回命令详细信息的字符串描述
func (this *CmdInfo) String() string {
	sb := common.NewStringBuilder()
	sb.Appendln(this.CmdName.String())
	if this.LogicType == nil {
		sb.Appendln("Logic说明：")
	} else {
		sb.Appendln("命令说明：")
	}
	sb.Appendln(this.CmdNote)
	for k, v := range this.ParamList {
		sb.Appendln(fmt.Sprintf("\t%s:%s 默认值：%s", k, v.ParamNote, v.DefaultVal))
	}
	return sb.ToString()
}

// AddParam 添加命令参数
func (this *CmdInfo) AddParam(pname, pnote, val string) {
	p := &ParamInfo{
		ParamName:  pname,
		ParamNote:  pnote,
		DefaultVal: val,
	}
	this.ParamList[p.ParamName] = p
}

// NewLogic 创建新的逻辑对象
func (this *CmdInfo) NewLogic() ILogic {
	result := reflect.New(this.LogicType).Interface().(ILogic)

	return result
}

// ParamInfo 命令参数信息
type ParamInfo struct {
	// 参数名 使用的时候需要加 -
	ParamName string
	// 参数说明
	ParamNote string
	// 默认值
	DefaultVal string
}

// NewParam 创建新的参数信息
func NewParam(pname, pnote, val string) (result *ParamInfo) {
	result = &ParamInfo{
		ParamName:  pname,
		ParamNote:  pnote,
		DefaultVal: val,
	}
	return
}

// InputCmd 输入的命令对象
type InputCmd struct {
	Cmd   *CmdInfo
	Param map[string]string
}

// NewLogic 创建并初始化逻辑对象
func (this *InputCmd) NewLogic() ILogic {
	result := this.Cmd.NewLogic()
	result.SetInputCmd(this)
	return result
}

// GetString 获取字符串参数
func (this *InputCmd) GetString(name string) string {
	v, ok := this.Param[name]
	if !ok {
		param := this.Cmd.ParamList[name]
		v = param.DefaultVal
	}
	return v
}

// GetInt 获取整型参数
func (this *InputCmd) GetInt(name string) int {
	v, ok := this.Param[name]
	if !ok {
		param := this.Cmd.ParamList[name]
		v = param.DefaultVal
	}
	return common.NewString(v).ToIntV()
}

// GetInt64 获取int64参数
func (this *InputCmd) GetInt64(name string) int64 {
	v, ok := this.Param[name]
	if !ok {
		param := this.Cmd.ParamList[name]
		v = param.DefaultVal
	}
	return common.NewString(v).ToInt64V()
}

// GetInt32 获取int32参数
func (this *InputCmd) GetInt32(name string) int32 {
	return int32(this.GetInt64(name))
}

// GetUint64 获取uint64参数
func (this *InputCmd) GetUint64(name string) uint64 {
	v, ok := this.Param[name]
	if !ok {
		param := this.Cmd.ParamList[name]
		v = param.DefaultVal
	}
	return common.NewString(v).ToUint64V()
}

// GetUint32 获取uint32参数
func (this *InputCmd) GetUint32(name string) uint32 {
	return uint32(this.GetUint64(name))
}

// GetBool 获取bool参数
func (this *InputCmd) GetBool(name string) bool {
	v, ok := this.Param[name]
	if !ok {
		param := this.Cmd.ParamList[name]
		v = param.DefaultVal
	}
	return common.NewString(v).ToBoolV()
}

// RunCmdF 命令执行函数类型
type RunCmdF func(cmd *InputCmd)

// ParseCmdF 命令解析函数类型，成功返回true
type ParseCmdF func(cmd *InputCmd) bool

// ILogic 命令逻辑接口
type ILogic interface {

	/* 委托用的函数 */

	// GenCmdParam 生成命令参数
	GenCmdParam(cmd *CmdInfo)
	// ParseCmd 解析命令，成功继续，失败显示命令参数
	ParseCmd(cmd *InputCmd) bool

	/* 生命周期 */

	// SetInputCmd 设置输出命令
	SetInputCmd(ic *InputCmd)

	// Destroy 销毁逻辑
	Destroy()
}
